package io.github.kouleen.manager.service;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import com.google.gson.reflect.TypeToken;
import io.github.kouleen.manager.ManagerX;
import io.github.kouleen.manager.domain.*;
import io.github.kouleen.minecraft.core.utils.GsonUtils;
import io.github.kouleen.minecraft.core.utils.StringUtils;
import org.apache.commons.io.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * @author zhangqing
 * @since 2025/1/25 14:26
 */
public class ManagerXConnectService {

    private static final Map<Long, TaskScheduledVO> taskScheduledMap = new HashMap<>();
    private static final Map<Long, BukkitTask> futureMap = new HashMap<>();
    private static final Map<UUID, String> players = new HashMap<>();
    private static final String LOCAL_PLUGIN_PATH = "plugins/ManagerX.jar";
    private static Logger logger;
    private static String URL_PAGE;
    private static String ACCESS_TOKEN_URL;
    private static String USERNAME;
    private static String PASSWORD;
    private static String ACCESS_TOKEN;
    private static String CHICKEN_CODE;
    private static String SERVER_CODE;
    private static String SERVER_HEART_URL;
    private static String SERVER_REGISTER_URL;
    private static TaskScheduledService taskScheduledService;

    public static void getAccToken() {
        String postUrl = ACCESS_TOKEN_URL + "?" + "username=" + USERNAME + "&" + "password=" + PASSWORD;
        HttpRequest httpRequestPost = HttpUtil.createPost(postUrl);
        try (HttpResponse httpResponse = httpRequestPost.execute()) {
            if (HttpStatus.HTTP_OK != httpResponse.getStatus()) {
                logger.info("getAccToken connect error");
                return;
            }
            String body = httpResponse.body();
            ResponseVO<SystemAuthorizationVO> authorizationVOResponseVO = GsonUtils.fromJson(body, new TypeToken<ResponseVO<SystemAuthorizationVO>>() {
            }.getType());
            if (!authorizationVOResponseVO.isSuccess()) {
                logger.info(authorizationVOResponseVO.getMessage());
                return;
            }
            ACCESS_TOKEN = authorizationVOResponseVO.getData().getAccess_token();
        }
    }

    public static List<TaskScheduledVO> getScheduled() {
        HttpRequest httpRequest = HttpUtil.createGet(URL_PAGE);
        httpRequest.header("token", ACCESS_TOKEN);
        try (HttpResponse httpResponse = httpRequest.execute()) {
            if (HttpStatus.HTTP_OK != httpResponse.getStatus()) {
                ManagerXConnectService.getAccToken();
                return Collections.emptyList();
            }
            String body = httpResponse.body();
            ResponseVO<IPage<TaskScheduledVO>> iPageResponseVO = GsonUtils.fromJson(body, new TypeToken<ResponseVO<IPage<TaskScheduledVO>>>() {
            }.getType());
            if (!iPageResponseVO.isSuccess()) {
                if (HttpStatus.HTTP_UNAUTHORIZED == Integer.parseInt(iPageResponseVO.getCode())) {
                    ManagerXConnectService.getAccToken();
                    return Collections.emptyList();
                }
                return Collections.emptyList();
            }
            return iPageResponseVO.getData().getRecords();
        }
    }

    public static void initConfig(ManagerX managerX) {
        managerX.saveDefaultConfig();
        managerX.reloadConfig();
        logger = managerX.getLogger();
        FileConfiguration managerXConfig = managerX.getConfig();
        logger.info("§2Loading config");
        URL_PAGE = managerXConfig.getString("setting.scheduled.url", "https://www.kouleen.cn/v1/task/scheduled/page");
        logger.info("§2scheduled_url: " + URL_PAGE);
        ACCESS_TOKEN_URL = managerXConfig.getString("setting.auth.url", "https://www.kouleen.cn/v2/system/auth/login");
        logger.info("§2access_token_url: " + ACCESS_TOKEN_URL);
        USERNAME = managerXConfig.getString("setting.auth.username", "minecraft");
        logger.info("§2username: " + USERNAME);
        PASSWORD = managerXConfig.getString("setting.auth.password", "minecraft");
        logger.info("§2password: " + PASSWORD);
        CHICKEN_CODE = managerXConfig.getString("chicken.code", "e521ed69-046e-49c2-899a-20e96a184f62");
        logger.info("§2chickenCode: " + CHICKEN_CODE);
        SERVER_CODE = managerXConfig.getString("server.code");
        logger.info("§2serverCode: " + SERVER_CODE);
        SERVER_HEART_URL = managerXConfig.getString("server.heart.url","https://www.kouleen.cn/v1/plugin/server/heart/");
        logger.info("§2serverHeartUrl: " + SERVER_HEART_URL);
        SERVER_REGISTER_URL = managerXConfig.getString("server.register.url","https://www.kouleen.cn/v1/plugin/server/register");
        logger.info("§2serverRegisterUrl: " + SERVER_REGISTER_URL);
        taskScheduledService = new TaskScheduledService(managerX.getLogger(), managerX);
    }

    public static void runTaskTimerAsynchronously(ManagerX managerX){
        // 执行注册修改操作
        runTaskTimerAsynchronouslyTaskRegisterServer(managerX,0L);
        // 执行毒鸡汤
        runTaskTimerAsynchronouslyTaskExecuteChicken(managerX);
        // 执行更新插件
        runTaskTimerAsynchronouslyUpdateCheckVersion(managerX);
    }

    private static void runTaskTimerAsynchronouslyTaskHeartServer(ManagerX managerX,long delay,long period) {
        Server server = managerX.getServer();
        // 延迟30秒，每三秒执行一次
        Bukkit.getScheduler().runTaskTimerAsynchronously(managerX, () -> {
            if (!StringUtils.hasText(SERVER_CODE)) {
                server.shutdown();
            }
            String getUrl = SERVER_HEART_URL + SERVER_CODE;
            HttpRequest httpRequest = HttpUtil.createGet(getUrl);
            try (HttpResponse httpResponse = httpRequest.execute()) {
                if (HttpStatus.HTTP_OK != httpResponse.getStatus()) {
                    return;
                }
                ResponseVO<?> iPageResponseVO = GsonUtils.fromJson(httpResponse.body(), ResponseVO.class);
                if (!iPageResponseVO.isSuccess()) {
                    if (HttpStatus.HTTP_INTERNAL_ERROR == Integer.parseInt(iPageResponseVO.getCode())) {
                        managerX.getLogger().severe(iPageResponseVO.getMessage());
                    }
                }
            }
        }, delay, period);
    }

    private static void runTaskTimerAsynchronouslyTaskRegisterServer(ManagerX managerX,long delay) {
        FileConfiguration managerXConfig = managerX.getConfig();
        Server server = managerX.getServer();
        Bukkit.getScheduler().runTaskLater(managerX, () ->{
            String serverName = managerXConfig.getString("server.name", server.getServerName());
            String gettUrl = SERVER_REGISTER_URL + "?serverCode" + SERVER_CODE + "&serverName=" + serverName;
            HttpRequest httpRequest = HttpUtil.createGet(gettUrl);
            try(HttpResponse httpResponse = httpRequest.execute()) {
                if (HttpStatus.HTTP_OK != httpResponse.getStatus()) {
                    // 延时10分钟再次请求
                    runTaskTimerAsynchronouslyTaskRegisterServer(managerX,12000L);
                    return;
                }
                ResponseVO<PluginServerVO> iPageResponseVO = GsonUtils.fromJson(httpResponse.body(), new TypeToken<ResponseVO<PluginServerVO>>(){}.getType());
                if (HttpStatus.HTTP_OK != Integer.parseInt(iPageResponseVO.getCode())) {
                    managerX.getLogger().severe(iPageResponseVO.getMessage());
                    // 延时3分钟再次请求
                    runTaskTimerAsynchronouslyTaskRegisterServer(managerX,3600L);
                    return;
                }
                PluginServerVO pluginServerVO = iPageResponseVO.getData();
                managerXConfig.set("server.name",pluginServerVO.getServerName());
                managerXConfig.set("server.code",pluginServerVO.getServerCode());
                SERVER_CODE = pluginServerVO.getServerCode();
                managerXConfig.set("server.heart.rate",pluginServerVO.getHeartRate());
                managerX.saveConfig();
                managerX.saveDefaultConfig();
                managerX.reloadConfig();
                // 延迟30秒，每三秒执行一次
                runTaskTimerAsynchronouslyTaskHeartServer(managerX,600L,600L);
            }

        }, delay);
    }

    private static void runTaskTimerAsynchronouslyTaskExecuteChicken(ManagerX managerX){
        Bukkit.getScheduler().runTaskTimerAsynchronously(managerX, () -> {
            List<TaskScheduledVO> taskScheduledVOList = ManagerXConnectService.getScheduled();
            for (TaskScheduledVO taskScheduled : taskScheduledVOList) {
                // 增加过滤
                if (CHICKEN_CODE.equals(taskScheduled.getTaskCode())){
                    Long id = taskScheduled.getId();
                    boolean needStart = false;
                    if (taskScheduledMap.containsKey(id)) {
                        if (!taskScheduled.equals(taskScheduledMap.get(id))) {
                            needStart = true;
                            taskScheduledService.stopScheduledTask(id, taskScheduledMap, futureMap);
                        }
                    } else {
                        needStart = true;
                    }
                    if (needStart && taskScheduled.getTaskStatus().equals(1)) {
                        taskScheduledService.startScheduledTask(taskScheduled, taskScheduledMap, futureMap, players);
                    }
                }
            }
            Iterator<Map.Entry<Long, TaskScheduledVO>> entryIterator = taskScheduledMap.entrySet().iterator();
            List<Long> idList = taskScheduledVOList.stream().map(TaskScheduledVO::getId).collect(Collectors.toList());
            while (entryIterator.hasNext()) {
                Long id = entryIterator.next().getKey();
                if (!idList.contains(id)) {
                    taskScheduledService.stopScheduledTask(id, taskScheduledMap, futureMap);
                }
            }
        }, 0L, 100L);
    }

    private static void runTaskTimerAsynchronouslyUpdateCheckVersion(ManagerX managerX) {
        FileConfiguration managerXConfig = managerX.getConfig();
        if (managerXConfig.getBoolean("setting.auto-update", true)) {
            logger.info("§2Checking your version...");
            // 默认60分钟
            long period = managerXConfig.getLong("setting.update-check-interval", 24);
            // 延迟120秒检查并更新
            Bukkit.getScheduler().runTaskTimerAsynchronously(managerX, () -> downloadUpdateCheckVersion(managerX), 120 * 20, period * 360 * 20);
        }
    }

    private static void downloadUpdateCheckVersion(ManagerX managerX) {
        // https://gitee.com/api/v5/repos/kouleen/manager-x/releases/tags/v1.12.2
        FileConfiguration managerXConfig = managerX.getConfig();
        String versionUrl = managerXConfig.getString("setting.last-version.url", "https://gitee.com/api/v5/repos/kouleen/manager-x/releases/tags/v1.12.2");
        HttpRequest httpRequest = HttpUtil.createGet(versionUrl);
        try (HttpResponse httpResponse = httpRequest.execute()) {
            if (HttpStatus.HTTP_OK != httpResponse.getStatus()) {
                logger.info("§5Checking version error status: §4" + httpResponse.getStatus());
                return;
            }
            String body = httpResponse.body();
            GiteeResponseVO giteeResponseVO = GsonUtils.fromJson(body, GiteeResponseVO.class);
            String responseVersion = giteeResponseVO.getName();
            int responseVersionNum = Integer.parseInt(responseVersion.replace(".", ""));
            PluginDescriptionFile pluginDescriptionFile = managerX.getDescription();
            String version = pluginDescriptionFile.getVersion();
            int versionNum = Integer.parseInt(version.replace(".", ""));
            if (responseVersionNum <= versionNum) {
                logger.info("§2No new version available");
                return;
            }
            List<GiteeBrowserVO> giteeResponseVOAssets = giteeResponseVO.getAssets();
            if (giteeResponseVOAssets == null || giteeResponseVOAssets.isEmpty()) {
                return;
            }
            GiteeBrowserVO giteeBrowserVO = giteeResponseVOAssets.get(0);
            logger.info("§2A new version of ManagerX is available: " + responseVersion + " (you're currently running " + version);
            logger.info("§2A Download it at: " + giteeBrowserVO.getBrowser_download_url());
            logger.info("§2Start downloading updates ...");

            File outputFile = HttpUtil.downloadFileFromUrl(giteeBrowserVO.getBrowser_download_url(), new File(LOCAL_PLUGIN_PATH + ".new"));
            // 备份旧插件
            File oldPlugin = new File(LOCAL_PLUGIN_PATH);
            // 替换为新插件
            FileUtils.copyFile(outputFile, oldPlugin);
            if (outputFile.exists()) {
                outputFile.delete();
            }
            logger.info("§2Download completed, please restart the server and reload.");
        } catch (IOException ioException) {
            logger.info("§4Checking version error: " + ioException.getMessage());
        }
    }

    public static Map<UUID, String> getPlayers() {
        return players;
    }
}
